package com.kehutong.payfees.admin;

import com.kehutong.common.math.CalculatorUtils;
import com.kehutong.common.util.Token;
import com.kehutong.payfees.entity.ChargeChoose;
import com.kehutong.payfees.entity.ChargeStandard;
import com.kehutong.payfees.entity.ChargeStandardItem;
import com.kehutong.payfees.enums.*;
import com.kehutong.payfees.service.ChargeChooseServiceImpl;
import com.kehutong.payfees.util.BasicClient;
import org.coraframework.authz.HasPermission;
import org.coraframework.inject.Inject;
import org.coraframework.json.JSONArray;
import org.coraframework.json.JSONObject;
import org.coraframework.mvc.MvcAction;
import org.coraframework.mvc.http.ReqMapping;
import org.coraframework.mvc.http.result.Result;
import org.coraframework.orm.Pool;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.Page;
import org.coraframework.util.EnumUtil;
import org.coraframework.util.Objects;

import java.math.BigDecimal;
import java.util.*;

@MvcAction
@ReqMapping("/admin/charge/standard")
public class ChargeStandardAction {

    @Inject
    private JdbcSession jdbcSession;
    @Inject
    private ChargeChooseServiceImpl chargeChooseService;
    @Inject
    private BasicClient basicClient;

    /**
     * 分页加载
     * @throws Exception
     */
    @HasPermission("charge:standard:view")
    @ReqMapping("/page")
    public Object page(JSONObject jsonObject) throws Exception {
        if(Objects.isEmpty(jsonObject.getString("feeTypeId"))
                || Objects.isEmpty(jsonObject.getString("communityNo"))) return new Page<>();

        Page<ChargeStandard> page = jdbcSession.findPage(ChargeStandard.class)
                .eq(jsonObject, "feeTypeId","communityNo")
                .like(jsonObject, "name")
                .eq("deleted", false)
                .order("createTime", "DESC")
                .page(jsonObject)
                .exe();

        page.getList().forEach(item -> {
            List<ChargeStandardItem> items = jdbcSession.findArray(ChargeStandardItem.class)
                    .eq("standardId", item.getId())
                    .order("startAmount","asc")
                    .exe();
            item.setStandardItems(items);
        });
        return page;
    }

    @HasPermission("charge:standard:view")
    @ReqMapping("/list")
    public Object list(JSONObject jsonObject) throws Exception {
        List<ChargeStandard> list = jdbcSession.findArray(ChargeStandard.class)
                .eq(jsonObject, "feeTypeId","communityNo")
                .order("createTime", "DESC")
                .eq("deleted", false)
                .exe();

        list.forEach(item -> {
            List<ChargeStandardItem> items = jdbcSession.findArray(ChargeStandardItem.class)
                    .eq("standardId", item.getId())
                    .order("startAmount","asc")
                    .exe();
            item.setStandardItems(items);
        });

        return list;
    }

    @HasPermission("charge:standard:edit")
    @ReqMapping("/delete")
    public Object delete(String id) throws Exception {
        ChargeStandard item = Pool.get(ChargeStandard.class, id);

        if (Objects.nonNull(item)) {
            List<ChargeChoose> chooses = jdbcSession.findArray(ChargeChoose.class)
                    .eq("standardId", item.getId())
                    .eq("deleted", false)
                    .exe();

            if(chooses.isEmpty()){
                item.setDeleted(true);
                jdbcSession.updateById(item);
            }else{
                return Result.error(0, "请移除本费项标准的绑定后，再删除");
            }
        }

        return Result.success();
    }

    @HasPermission("charge:standard:view")
    @ReqMapping("/get")
    public Object get(Token session, String id) {
        ChargeStandard item = Pool.get(ChargeStandard.class, id);
        return Result.success(item);
    }

    @HasPermission("charge:standard:edit")
    @ReqMapping("/update")
    public Object update(Token token, JSONObject jsonObject) throws Exception {
        ChargeStandard standard = getChargeStandard(token, jsonObject);

        if (existSameName(standard)) {
            return Result.error(0, standard.getName() + "已存在标准名称，请勿重复添加");
        }

        if(Integer.valueOf(standard.getChargeMode().getId()) > 4) {
            updateNodes(standard, jsonObject.getJSONArray("items"));
        }else{
            if(CalculatorUtils.getDecimalPlace(standard.getPrice()) > 2){
                return Result.error(0, standard.getName() + "单位价格 不能大于2位小数");
            }
            standard.setItems(null);
        }
        jdbcSession.updateById(standard);

        List<ChargeChoose> chooses = jdbcSession.findArray(ChargeChoose.class)
                .eq("standardId",standard.getId())
                .eq("feeTypeId", standard.getFeeTypeId())
                .exe();

        for (ChargeChoose choose: chooses) {
            choose.setStandardName(standard.getName());
            choose.setPrice(standard.getPrice());
            choose.setChargeMode(standard.getChargeMode());
            choose.setComputeType(standard.getComputeType());
            choose.setUnitPrice(standard.getUnitPrice());

            JSONObject data = basicClient.getHouseById(token, choose.getHouseNo());
            if(choose.getChargeMode() == ChargeModeType.AREA){// 面积*单价
                choose.setAmount(data.getBigDecimal("payArea"));
                if(Objects.nonNull(choose.getAmount())){
                    choose.setTotal(BigDecimal.ZERO.add(choose.getPrice()).multiply(choose.getAmount()));
                }else{
                    choose.setTotal(null);
                }
            }else if(choose.getChargeMode() == ChargeModeType.COVER){// 套数*单价
                choose.setAmount(new BigDecimal(1));
                if(Objects.nonNull(choose.getAmount())){
                    choose.setTotal(BigDecimal.ZERO.add(choose.getPrice()).multiply(choose.getAmount()));
                }else{
                    choose.setTotal(null);
                }
            }else if(choose.getChargeMode() == ChargeModeType.TIER) {// 层数*单价
                if (Objects.nonEmpty(data.getString("floorName"))) {
                    // 字符串截取 **楼前面的数字
                    String floorNumber = getQuantity(data.getString("floorName"));
                    choose.setAmount(new BigDecimal(floorNumber));
                    if(Objects.nonNull(choose.getAmount())){
                        choose.setTotal(BigDecimal.ZERO.add(choose.getPrice()).multiply(choose.getAmount()));
                    }else{
                        choose.setTotal(null);
                    }
                }
            }else if(choose.getChargeMode() == ChargeModeType.AMOUNTLADDER){// 用量阶梯价
                choose.setAmount(null);
                choose.setTotal(null);
            } else if(choose.getChargeMode() == ChargeModeType.AREALADDER){// 面积阶梯价
                choose.setAmount(data.getBigDecimal("payArea"));
                if(Objects.nonNull(choose.getAmount())) {
                    chargeChooseService.getTotal(choose);
                }else{
                    choose.setTotal(null);
                }
            } else if(choose.getChargeMode() == ChargeModeType.TIERLADDER){// 层数阶梯价
                // 字符串截取 **楼前面的数字
                String floorNumber = getQuantity(data.getString("floorName"));
                choose.setAmount(new BigDecimal(floorNumber));
                if(Objects.nonNull(choose.getAmount())) {
                    chargeChooseService.getTotal(choose);
                }else{
                    choose.setTotal(null);
                }
            } else{
                choose.setAmount(null);
                choose.setTotal(null);
            }
        }
        jdbcSession.updateById(chooses);

        return Result.success();
    }

    @HasPermission("charge:standard:edit")
    @ReqMapping("/save")
    public Object save(Token token, JSONObject jsonObject) throws Exception {
        ChargeStandard standard = getChargeStandard(token, jsonObject);

        if (existSameName(standard)) {
            return Result.error(0, standard.getName() + "已存在标准名称，请勿重复添加");
        }

        if(Integer.valueOf(standard.getChargeMode().getId()) > 4){
            addNodes(standard, jsonObject.getJSONArray("items"));
        }else{
            if(CalculatorUtils.getDecimalPlace(standard.getPrice()) > 2){
                return Result.error(0, standard.getName() + "单位价格 不能大于2位小数");
            }
            standard.setItems(null);
        }

        jdbcSession.insert(standard);

        return Result.success();
    }

    /**
     * 是否存在重名
     */
    private boolean existSameName(ChargeStandard standard) {
        return !jdbcSession.findArray(ChargeStandard.class)
                .eq("name", standard.getName())
                .eq("communityNo", standard.getCommunityNo())
                .eq("feeTypeId", standard.getFeeTypeId())
                // 传入的entity已携带id
                .noEq("id", standard.getId())
                .eq("deleted", false)
                .exe().isEmpty();
    }

    private void addNodes(ChargeStandard standard, JSONArray jsonArray) {
        List<String> itemList = new ArrayList<>(Math.max(4, jsonArray.size()));

        for (int i = 0; i < jsonArray.size(); i ++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            ChargeStandardItem item = Pool.newInstance(ChargeStandardItem.class);
            item.setChargeMode(EnumUtil.getEnum(ItemChargeModeType.class, jsonObject.getString("chargeMode")));
            item.setEndAmount(jsonObject.getBigDecimal("endAmount"));
            item.setStartAmount(jsonObject.getBigDecimal("startAmount"));
            item.setPrice(jsonObject.getBigDecimal("price"));
            item.setStandardId(standard.getId());
            jdbcSession.insert(item);

            itemList.add(item.getId());
        }
        standard.setItems(itemList);
    }

    private void updateNodes(ChargeStandard standard, JSONArray jsonArray) {
        List<String> itemList = new ArrayList<>(Math.max(4, jsonArray.size()));
        for (int i = 0; i < jsonArray.size(); i ++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            final String id = jsonObject.getString("id");

            ChargeStandardItem item;
            if (Objects.isEmpty(id)) {
                item = Pool.newInstance(ChargeStandardItem.class);
            } else {
                item = Pool.get(ChargeStandardItem.class, id);
            }

            item.setChargeMode(EnumUtil.getEnum(ItemChargeModeType.class, jsonObject.getString("chargeMode")));
            item.setEndAmount(jsonObject.getBigDecimal("endAmount"));
            item.setStartAmount(jsonObject.getBigDecimal("startAmount"));
            item.setPrice(jsonObject.getBigDecimal("price"));
            item.setStandardId(standard.getId());

            if (Objects.isEmpty(id)) {
                jdbcSession.insert(item);
            } else {
                jdbcSession.updateById(item);
            }
            itemList.add(item.getId());
        }

        deleteNodes(standard, itemList);
        standard.setItems(itemList);
    }

    private void deleteNodes(ChargeStandard standard, List<String> itemList) {
        List<String> oldList = standard.getItems();
        Iterator<String> it = oldList.iterator();
        while (it.hasNext()) {
            if (itemList.contains(it.next())) {
                it.remove();
            }
        }

        for (String itemNo : oldList) {
            jdbcSession.deleteById(ChargeStandardItem.class, itemNo);
        }
    }

    private ChargeStandard getChargeStandard(Token token, JSONObject jsonObject) throws Exception {

        ChargeStandard standard = null;
        String id = jsonObject.getString("id");
        if(Objects.nonEmpty(id)){
            standard = Pool.get(ChargeStandard.class, id);
        } else {
            standard = Pool.newInstance(ChargeStandard.class);
        }

        standard.setCommunityNo(jsonObject.getString("communityNo"));
        standard.setFeeTypeId(jsonObject.getString("feeTypeId"));
        standard.setFeeTypeName(jsonObject.getString("feeTypeName"));
        standard.setName(jsonObject.getString("name"));
        standard.setPrice(jsonObject.getBigDecimal("price"));
        standard.setChargeMode(EnumUtil.getEnum(ChargeModeType.class, jsonObject.getString("chargeMode")));
        if(Objects.nonEmpty(jsonObject.getString("priceCycle"))){
            standard.setPriceCycle(EnumUtil.getEnum(PriceCycle.class, jsonObject.getString("priceCycle")));
        }
        standard.setComputeType(EnumUtil.getEnum(ComputeType.class, jsonObject.getString("computeType")));
        standard.setUnitPrice(EnumUtil.getEnum(UnitPrice.class, jsonObject.getString("unitPrice")));

        setDepartmentNo(standard, token.getCompanyNo());

        return standard;
    }

    public static String getQuantity(String regular){
        int index = 0;
        for (int i = 0; i < regular.length(); i++) {
            char c = regular.charAt(i);
            if (Character.isDigit(c)) {
                if (i == regular.length() - 1) {
                    index = i + 1;
                } else {
                    index = i;
                }
                continue;
            } else {
                index = i;
                break;
            }
        }
        return regular.substring(0, index);
    }

    private void setDepartmentNo(ChargeStandard entity, String companyNo) throws Exception {
        JSONObject community = basicClient.getCommunityById(companyNo,
                entity.getCommunityNo());
        if(Objects.nonEmpty(community)){
            String parent_id = community.getString("parent_id");
            if(Objects.nonEmpty(parent_id)){
                entity.setDepartmentNo(parent_id);
            }
            JSONArray parent_ids = community.getJSONArray("parent_ids");
            if(Objects.nonEmpty(parent_ids)){
                List<String> departmentNos = JSONObject.parseArray(parent_ids.toJSONString(), String.class);
                entity.setDepartmentNos(departmentNos);
            }
        }
    }
}
